/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package assisisw.smartcal.entitysubsystem;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;

/**
 *
 * @author Francesco
 */
@Entity ( name = "User" )
@Table ( name = "users" , catalog = "smartcal" )
@SecondaryTable ( name = "token" , catalog = "smartcal" ,
                  pkJoinColumns = { @PrimaryKeyJoinColumn ( name = "usermail" , referencedColumnName = "mail") } )
public class User implements Serializable 
{
 
    // Static Methods
    
    public static void copySimpleData ( User src , User dest )
    {
        dest.setPassword ( src.getPassword () );
        dest.setActive ( src.isActive () );
        dest.setFirstname ( src.getFirstname () ) ;
        dest.setLastname ( src.getLastname () );
    }
    
    // Instance Fields
    
    /***/
    @Id ()
    @NotNull
    @Column ( name = "mail" , updatable = false , unique = true , table = "users" , nullable = false , length = 20 )
    private String mail ;

    /***/
    @Column ( name = "firstname" , nullable = true , table = "users" , length = 15 )
    private String firstname ;
    
    /***/
    @Column ( name = "lastname" , nullable = true , table = "users" , length = 15 )
    private String lastname ;
   
    /***/
    @NotNull 
    @Column ( name = "password" , updatable = true , table = "users" ) 
    private String password ;
   
    /***/
    @NotNull
    @Column ( name = "active" , updatable = true , table = "users" )
    private Boolean active ;
   
    /***/
    @NotNull
    @Column ( name = "token" , table = "token" , length = 40 )
    private String token ;
  
    /***/
    @NotNull
    @OneToMany ( mappedBy = "owner" , 
                 fetch = FetchType.EAGER , 
                 orphanRemoval = true ,
                 targetEntity = Calendar.class ,
                 cascade = { CascadeType.DETACH , CascadeType.MERGE , CascadeType.PERSIST , CascadeType.REFRESH , CascadeType.REMOVE } )
    private List < Calendar > ownedCalendars ;
    
    /***/
    @NotNull
    @ManyToMany ( mappedBy = "peopleWhoCanAccess" , 
                  fetch = FetchType.EAGER , 
                  cascade = { CascadeType.DETACH , CascadeType.REFRESH } , 
                  targetEntity = Calendar.class )
    @JoinTable ( name = "smartcal.sharedcalendar" ,
                 joinColumns = { @JoinColumn ( name = "usermail" , referencedColumnName = "mail" ) } ,
                 inverseJoinColumns = { @JoinColumn ( name = "calendarid" , referencedColumnName = "id" ) } )
    private List < Calendar > sharedCalendars ;
    
    /***/
    @NotNull
    @ManyToMany ( mappedBy = "invitedUsers" , 
                  fetch = FetchType.EAGER , 
                  cascade = { CascadeType.DETACH , CascadeType.REFRESH } ,
                  targetEntity = Event.class )
    @JoinTable ( name = "smartcal.invitation" ,
                 joinColumns = { @JoinColumn ( name = "usermail" , referencedColumnName = "mail" ) } ,
                 inverseJoinColumns = {  @JoinColumn ( name = "eventid" , referencedColumnName = "id" ) } )
    private Collection < Event > invitedEvents ;
    
    /***/
    @NotNull
    @OneToMany ( mappedBy = "recipient" , 
                 fetch = FetchType.EAGER , 
                 cascade = { CascadeType.ALL } , 
                 orphanRemoval = true )
    private List < Notification > notifications ;
    
    // Instance Methods
    
    /***/
    public User () 
    {
        ownedCalendars = new ArrayList <> ( 0 ) ;
        sharedCalendars = new ArrayList <> ( 0 ) ;
        invitedEvents = new LinkedList <> () ;
        notifications = new LinkedList <> () ;
        active = false ; 
        token = null ;
    }
   
    /**
     * @param mail 
     * @param firstname 
     * @param lastname 
     * @param password 
     * @throws IllegalArgumentException
     */
    public User ( String mail , String firstname , String lastname , String password ) 
    {
        this () ;
        if ( mail != null && password != null && ! mail.isEmpty () && ! password.isEmpty () )
        {
            this.mail = mail ;
            this.firstname = firstname ;
            this.lastname = lastname ;
            this.password = password ;
        }
        else
            throw new IllegalArgumentException () ;
    }
    
    /**
     * AS THE SUPER'S ONE
     */
    @Override
    public int hashCode () 
    {
        int hash = 0;
        hash = mail.hashCode () ;
        return hash;
    }

    /**
     * AS THE SUPER'S ONE.
     */
    @Override
    public boolean equals ( Object object ) 
    {
        User other ;
        boolean res ;
        if ( object instanceof User )
        {
            other = ( User ) object ;
            res = mail.equalsIgnoreCase ( other.getMail () ) ;
        }
        else
            res = false ;
        return res ;
    }

    /**
     * AS THE SUPER'S ONE.
     */
    @Override
    public String toString () 
    {
        return "User :\nMail : " + mail ;
    }

    public void setMail ( String mail ) 
    {
        this.mail = mail ;
    }
    
    /**
     * @return the eMail
     */
    public String getMail () 
    {
        return mail;
    }

    public void setFirstname ( String firstname ) 
    {
        this.firstname = firstname ;
    }
    
    /**
     * @return the firstName
     */
    public String getFirstname () 
    {
        return firstname;
    }

    public void setLastname ( String lastname ) 
    {
        this.lastname = lastname ;
    }
    
    /**
     * @return the lastName
     */
    public String getLastname () 
    {
        return lastname;
    }

    /**
     * @param password
     * @throws IllegalArgumentException
     */
    public void setPassword ( String password ) 
    {
        if ( password != null && ! password.isEmpty () )
            this.password = password ;
        else
            throw new IllegalArgumentException () ;
    }
    
    /**
     * @return the password
     */
    public String getPassword () 
    {
        return password;
    }

    /***/
    public void activate () 
    {
        active = true ;
    }
    
    /***/
    public void deactivate () 
    {
        active = false ;
    }
    
    public void setActive ( Boolean active )
    {
        this.active = active ;
    }
    
    public boolean getActive () 
    {
        return active ;
    }
    
    /***/
    public boolean isActive () 
    {
        return active ;
    }
    
    /***/
    public void setToken ( String token ) 
    {
        this.token = token ;
    }
    
    /***/
    public String getToken () 
    {
        return token ;
    }
    
    public void setOwnedCalendars ( List < Calendar > ownedCalendars ) 
    {
        this.ownedCalendars = ownedCalendars ;
    }
    
    /**
     * @return
     */
    public List < Calendar > getOwnedCalendars () 
    {
        return ownedCalendars ;
    }
    
    public void setSharedCalendars ( List < Calendar > sharedCalendars ) 
    {
        this.sharedCalendars = sharedCalendars ;
    }
    
    /**
     * @return
     */
    public List < Calendar > getSharedCalendars () 
    {
        return sharedCalendars ;
    }
    
    /**
     * @return
     */
    public Collection < Event > getInvitedEvents () 
    {
        return invitedEvents ;
    }
 
    public void setNotifications ( List < Notification > notifications ) 
    {
        this.notifications = notifications ;
    }
    
    /**
     * @return
     */
    public List < Notification > getNotifications () 
    {
        return notifications ;
    }
    
}
